import { defined } from '../../Source/Cesium.js';
import { EarthOrientationParameters } from '../../Source/Cesium.js';
import { JulianDate } from '../../Source/Cesium.js';
import { TimeStandard } from '../../Source/Cesium.js';

describe('Core/EarthOrientationParameters', function() {

    var officialLeapSeconds;

    beforeAll(function() {
        officialLeapSeconds = JulianDate.leapSeconds.slice(0);
    });

    afterEach(function() {
        JulianDate.leapSeconds = officialLeapSeconds.slice(0);
    });

    it('adds leap seconds found in the data by default', function() {
        var eop = new EarthOrientationParameters({
            data : {
                'columnNames' : ['dateIso8601',
                                 'modifiedJulianDateUtc',
                                 'xPoleWanderRadians',
                                 'yPoleWanderRadians',
                                 'xCelestialPoleOffsetRadians',
                                 'yCelestialPoleOffsetRadians',
                                 'ut1MinusUtcSeconds',
                                 'taiMinusUtcSeconds',
                                 'lengthOfDayCorrectionSeconds'],
                'samples' : ['2011-08-25T00:00:00Z', 55798.0, 2.117957047295119e-7, 2.111518721609984e-6, 3.393695767766752e-11, 3.3452143996557983e-10, -0.2908948, 34.0, -2.956e-4,
                             '2011-08-26T00:00:00Z', 55799.0, 2.193297093339541e-7, 2.115460256837405e-6, -8.241832578862112e-11, 5.623838700870617e-10, -0.29065, 34.5, -1.824e-4,
                             '2011-08-27T00:00:00Z', 55800.0, 2.262286080161428e-7, 2.1191157519929706e-6, -3.490658503988659e-10, 6.981317007977318e-10, -0.2905572, 34.5, 1.9e-6,
                             '2011-08-28T00:00:00Z', 55801.0, 2.3411652660779493e-7, 2.122751854601292e-6, -6.205615118202061e-10, 7.853981633974483e-10, -0.2907007, 34.5, 2.695e-4]
            }
        });
        expect(eop).not.toBeNull();

        var leapSeconds = JulianDate.leapSeconds;
        expect(leapSeconds.length).toBe(officialLeapSeconds.length + 1);

        var newDate = new JulianDate(2455799.5, 34.5, TimeStandard.TAI);
        var foundNew = false;
        var previousDate;

        for (var i = 0, len = leapSeconds.length; i < len; ++i) {
            var leapSecond = leapSeconds[i];
            if (leapSecond.julianDate.equals(newDate)) {
                foundNew = true;
            }

            if (defined(previousDate)) {
                expect(JulianDate.compare(previousDate, leapSecond.julianDate)).toBeLessThan(0);
            }

            previousDate = leapSecond.julianDate;
        }

        expect(foundNew).toBe(true);
    });

    it('does not add leap seconds if told not to do so', function() {
        var eop = new EarthOrientationParameters({
            addNewLeapSeconds : false,
            data : {
                'columnNames' : ['dateIso8601',
                                 'modifiedJulianDateUtc',
                                 'xPoleWanderRadians',
                                 'yPoleWanderRadians',
                                 'xCelestialPoleOffsetRadians',
                                 'yCelestialPoleOffsetRadians',
                                 'ut1MinusUtcSeconds',
                                 'taiMinusUtcSeconds',
                                 'lengthOfDayCorrectionSeconds'],
                'samples' : ['2011-08-25T00:00:00Z', 55798.0, 2.117957047295119e-7, 2.111518721609984e-6, 3.393695767766752e-11, 3.3452143996557983e-10, -0.2908948, 35.0, -2.956e-4,
                             '2011-08-26T00:00:00Z', 55799.0, 2.193297093339541e-7, 2.115460256837405e-6, -8.241832578862112e-11, 5.623838700870617e-10, -0.29065, 36.0, -1.824e-4,
                             '2011-08-27T00:00:00Z', 55800.0, 2.262286080161428e-7, 2.1191157519929706e-6, -3.490658503988659e-10, 6.981317007977318e-10, -0.2905572, 36.0, 1.9e-6,
                             '2011-08-28T00:00:00Z', 55801.0, 2.3411652660779493e-7, 2.122751854601292e-6, -6.205615118202061e-10, 7.853981633974483e-10, -0.2907007, 36.0, 2.695e-4]
            }
        });
        expect(eop).not.toBeNull();

        var leapSeconds = JulianDate.leapSeconds;
        expect(leapSeconds.length).toBe(officialLeapSeconds.length);
    });

    describe('loading eop', function() {

        function linearInterp(dx, y1, y2) {
            return y1 + dx * (y2 - y1);
        }

        it('interpolates data correctly under normal circumstances', function() {
            var eopDescription = {
                url : undefined,
                data : {
                    'columnNames' : ['dateIso8601',
                                     'modifiedJulianDateUtc',
                                     'xPoleWanderRadians',
                                     'yPoleWanderRadians',
                                     'xCelestialPoleOffsetRadians',
                                     'yCelestialPoleOffsetRadians',
                                     'ut1MinusUtcSeconds',
                                     'taiMinusUtcSeconds',
                                     'lengthOfDayCorrectionSeconds'],
                    'samples' : ['2011-07-01T00:00:00Z', 55743.0, 2.117957047295119e-7, 2.111518721609984e-6, 3.393695767766752e-11, 3.3452143996557983e-10, -0.2908948, 34.0, -2.956e-4,
                                 '2011-07-02T00:00:00Z', 55744.0, 2.193297093339541e-7, 2.115460256837405e-6, -8.241832578862112e-11, 5.623838700870617e-10, -0.29065, 34.0, -1.824e-4,
                                 '2011-07-03T00:00:00Z', 55745.0, 2.262286080161428e-7, 2.1191157519929706e-6, -3.490658503988659e-10, 6.981317007977318e-10, -0.2905572, 34.0, 1.9e-6,
                                 '2011-07-04T00:00:00Z', 55746.0, 2.3411652660779493e-7, 2.122751854601292e-6, -6.205615118202061e-10, 7.853981633974483e-10, -0.2907007, 34.0, 2.695e-4]
                }
            };

            var eop = new EarthOrientationParameters(eopDescription);

            var date = JulianDate.fromIso8601('2011-07-02T12:34:56Z');
            var result = eop.compute(date);
            var nColumns = eopDescription.data.columnNames.length;
            var x0 = eopDescription.data.samples[1 * nColumns + 2];
            var x1 = eopDescription.data.samples[2 * nColumns + 2];
            var dt = JulianDate.secondsDifference(date, JulianDate.fromIso8601(eopDescription.data.samples[nColumns])) / 86400.0;
            var expected = linearInterp(dt, x0, x1);
            expect(result.xPoleWander).toEqualEpsilon(expected, 1e-22);
            x0 = eopDescription.data.samples[1 * nColumns + 3];
            x1 = eopDescription.data.samples[2 * nColumns + 3];
            expected = linearInterp(dt, x0, x1);
            expect(result.yPoleWander).toEqualEpsilon(expected, 1e-22);
            x0 = eopDescription.data.samples[1 * nColumns + 4];
            x1 = eopDescription.data.samples[2 * nColumns + 4];
            expected = linearInterp(dt, x0, x1);
            expect(result.xPoleOffset).toEqualEpsilon(expected, 1e-22);
            x0 = eopDescription.data.samples[1 * nColumns + 5];
            x1 = eopDescription.data.samples[2 * nColumns + 5];
            expected = linearInterp(dt, x0, x1);
            expect(result.yPoleOffset).toEqualEpsilon(expected, 1.0e-22);
            x0 = eopDescription.data.samples[1*nColumns + 6];
            x1 = eopDescription.data.samples[2*nColumns + 6];
            expected = linearInterp(dt, x0, x1);
            expect(result.ut1MinusUtc).toEqualEpsilon(expected, 1.0e-15);
        });

        it('interpolates UT1 correctly over a leap second', function() {
            var eopDescription = {
                    url : undefined,
                    data : {
                        'columnNames':['dateIso8601',
                                       'modifiedJulianDateUtc',
                                       'xPoleWanderRadians',
                                       'yPoleWanderRadians',
                                       'xCelestialPoleOffsetRadians',
                                       'yCelestialPoleOffsetRadians',
                                       'ut1MinusUtcSeconds',
                                       'taiMinusUtcSeconds',
                                       'lengthOfDayCorrectionSeconds'],
                        'samples':[
                                    '2008-12-30T00:00:00Z',54830.0,-4.6702101901281595e-8,6.989752766028624e-7,-7.80550026586353e-10,-1.052045688007693e-9,-0.5911461,33.0,5.7e-4,
                                    '2008-12-31T00:00:00Z',54831.0,-6.507169227852191e-8,7.02873178598983e-7,-7.80550026586353e-10,-1.8907733563271904e-9,-0.59187,33.0,8.303e-4,
                                    '2009-01-01T00:00:00Z',54832.0,-8.25443773457096e-8,7.089575902969077e-7,-8.047907106418297e-10,-2.0604581447155277e-9,0.4071533,34.0,0.0010604,
                                    '2009-01-02T00:00:00Z',54833.0,-9.884381330461219e-8,7.147559619229779e-7,-8.435758051305926e-10,-1.8228994409718553e-9,0.4059739,34.0,0.0012279,
                                    '2009-01-03T00:00:00Z',54834.0,-1.1269009203710055e-7,7.226826656091187e-7,-9.066015836748322e-10,-1.5029224114395617e-9,0.404674,34.0,0.0013014
                                    ]
                    }
            };

            var eop = new EarthOrientationParameters(eopDescription);
            var dateAtLeapSecond = JulianDate.fromIso8601('2009-01-01T00:00:00Z');
            var dateSlightlyBefore = JulianDate.addSeconds(dateAtLeapSecond, -1.0, new JulianDate());
            var dateSlightlyAfter = JulianDate.addSeconds(dateAtLeapSecond, 1.0, new JulianDate());
            var nColumns = eopDescription.data.columnNames.length;
            var x0 = eopDescription.data.samples[1*nColumns + 6];
            var x1 = eopDescription.data.samples[2*nColumns + 6];
            var x2 = eopDescription.data.samples[3*nColumns + 6];
            var t0 = JulianDate.fromIso8601(eopDescription.data.samples[nColumns]);
            var t1 = JulianDate.fromIso8601(eopDescription.data.samples[2*nColumns]);
            var dt = JulianDate.secondsDifference(dateSlightlyBefore, t0) / (86400.0 + 1);
            // Adjust for leap second when interpolating
            var expectedBefore = linearInterp(dt, x0, (x1 - 1));
            var resultBefore = eop.compute(dateSlightlyBefore);
            expect(resultBefore.ut1MinusUtc).toEqualEpsilon(expectedBefore, 1.0e-15);
            var expectedAt = eopDescription.data.samples[2*nColumns + 6];
            var resultAt = eop.compute(dateAtLeapSecond);
            expect(resultAt.ut1MinusUtc).toEqualEpsilon(expectedAt, 1.0e-15);
            dt = JulianDate.secondsDifference(dateSlightlyAfter, t1) / (86400.0);
            var expectedAfter = linearInterp(dt, x1, x2);
            var resultAfter = eop.compute(dateSlightlyAfter);
            expect(resultAfter.ut1MinusUtc).toEqualEpsilon(expectedAfter, 1.0e-15);
            // Check to make sure the values are (correctly) discontinuous
            expect(Math.abs(resultBefore.ut1MinusUtc - resultAfter.ut1MinusUtc) > 0.5).toEqual(true);
        });
    });
});
